/*
 * 纯C语言实现Redis的连接及基本操作（get, hget, lpop, hset, expire, ttl, rpush, lrange, ltrim等）
 * 不使用hiredis库，直接用原生C语言通过socket与Redis通信
 * 仅支持简单的字符串命令和回复解析
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>

#define REDIS_PORT 6379
#define REDIS_REPLY_BUF 4096

typedef struct {
    int sockfd;
} redisContext;

// 连接Redis服务器
redisContext* redis_connect(const char* hostname, int port) {
    struct sockaddr_in serv_addr;
    struct hostent *server;
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("socket");
        return NULL;
    }
    server = gethostbyname(hostname);
    if (server == NULL) {
        fprintf(stderr, "No such host\n");
        close(sockfd);
        return NULL;
    }
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);
    serv_addr.sin_port = htons(port);

    if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("connect");
        close(sockfd);
        return NULL;
    }
    redisContext* ctx = (redisContext*)malloc(sizeof(redisContext));
    ctx->sockfd = sockfd;
    return ctx;
}

// 发送命令并接收回复
int redis_send_command(redisContext* c, const char* cmd, char* reply_buf, size_t reply_buf_size) {
    size_t len = strlen(cmd);
    ssize_t sent = send(c->sockfd, cmd, len, 0);
    if (sent != (ssize_t)len) {
        perror("send");
        return -1;
    }
    ssize_t recvd = recv(c->sockfd, reply_buf, reply_buf_size - 1, 0);
    if (recvd <= 0) {
        perror("recv");
        return -1;
    }
    reply_buf[recvd] = '\0';
    return 0;
}

// 解析简单字符串回复（+OK\r\n 或 $len\r\nvalue\r\n 或 *N\r\n...）
char* redis_parse_simple_reply(const char* reply) {
    if (reply[0] == '+') {
        // +OK\r\n
        return strdup(reply + 1);
    } else if (reply[0] == '$') {
        // $len\r\nvalue\r\n
        int len = atoi(reply + 1);
        if (len < 0) return NULL;
        const char* p = strstr(reply, "\r\n");
        if (!p) return NULL;
        p += 2;
        char* val = (char*)malloc(len + 1);
        strncpy(val, p, len);
        val[len] = '\0';
        return val;
    } else if (reply[0] == ':') {
        // :integer\r\n
        return strdup(reply + 1);
    } else if (reply[0] == '-') {
        // -Error message
        return NULL;
    }
    return NULL;
}

// 解析数组回复（如LRANGE等返回的*count\r\n$len\r\nvalue\r\n...）
// 返回一个char**数组，*out_count为元素个数，需调用free_redis_array释放
char** redis_parse_array_reply(const char* reply, int* out_count) {
    if (reply[0] != '*') return NULL;
    int count = atoi(reply + 1);
    if (count <= 0) {
        *out_count = 0;
        return NULL;
    }
    char** arr = (char**)malloc(sizeof(char*) * count);
    const char* p = reply;
    int i;
    for (i = 0; i < count; ++i) {
        p = strstr(p, "\r\n");
        if (!p) break;
        p += 2;
        if (*p != '$') break;
        int len = atoi(p + 1);
        if (len < 0) {
            arr[i] = NULL;
            continue;
        }
        const char* val_start = strstr(p, "\r\n");
        if (!val_start) break;
        val_start += 2;
        arr[i] = (char*)malloc(len + 1);
        strncpy(arr[i], val_start, len);
        arr[i][len] = '\0';
        p = val_start + len;
    }
    *out_count = i;
    return arr;
}

void free_redis_array(char** arr, int count) {
    if (!arr) return;
    for (int i = 0; i < count; ++i) {
        if (arr[i]) free(arr[i]);
    }
    free(arr);
}

// GET操作
char* redis_get(redisContext* c, const char* key) {
    char cmd[256], reply[REDIS_REPLY_BUF];
    snprintf(cmd, sizeof(cmd), "*2\r\n$3\r\nGET\r\n$%zu\r\n%s\r\n", strlen(key), key);
    if (redis_send_command(c, cmd, reply, sizeof(reply)) != 0) return NULL;
    return redis_parse_simple_reply(reply);
}

// HGET操作
char* redis_hget(redisContext* c, const char* hash, const char* field) {
    char cmd[512], reply[REDIS_REPLY_BUF];
    snprintf(cmd, sizeof(cmd), "*3\r\n$4\r\nHGET\r\n$%zu\r\n%s\r\n$%zu\r\n%s\r\n",
             strlen(hash), hash, strlen(field), field);
    if (redis_send_command(c, cmd, reply, sizeof(reply)) != 0) return NULL;
    return redis_parse_simple_reply(reply);
}

// LPOP操作
char* redis_lpop(redisContext* c, const char* list) {
    char cmd[256], reply[REDIS_REPLY_BUF];
    snprintf(cmd, sizeof(cmd), "*2\r\n$4\r\nLPOP\r\n$%zu\r\n%s\r\n", strlen(list), list);
    if (redis_send_command(c, cmd, reply, sizeof(reply)) != 0) return NULL;
    return redis_parse_simple_reply(reply);
}

// RPUSH操作
int redis_rpush(redisContext* c, const char* list, const char* value) {
    char cmd[512], reply[REDIS_REPLY_BUF];
    snprintf(cmd, sizeof(cmd), "*3\r\n$5\r\nRPUSH\r\n$%zu\r\n%s\r\n$%zu\r\n%s\r\n",
             strlen(list), list, strlen(value), value);
    if (redis_send_command(c, cmd, reply, sizeof(reply)) != 0) return -1;
    // :N\r\n
    if (reply[0] == ':') {
        return atoi(reply + 1);
    }
    return -1;
}

// LRANGE操作
// 返回char**数组，*out_count为元素个数，需调用free_redis_array释放
char** redis_lrange(redisContext* c, const char* list, int start, int end, int* out_count) {
    char cmd[256], reply[REDIS_REPLY_BUF];
    snprintf(cmd, sizeof(cmd), "*4\r\n$6\r\nLRANGE\r\n$%zu\r\n%s\r\n$%d\r\n%d\r\n$%d\r\n%d\r\n",
             strlen(list), list,
             (int)snprintf(NULL, 0, "%d", start), start,
             (int)snprintf(NULL, 0, "%d", end), end);
    if (redis_send_command(c, cmd, reply, sizeof(reply)) != 0) {
        *out_count = 0;
        return NULL;
    }
    return redis_parse_array_reply(reply, out_count);
}

// LTRIM操作
int redis_ltrim(redisContext* c, const char* list, int start, int end) {
    char cmd[256], reply[REDIS_REPLY_BUF];
    snprintf(cmd, sizeof(cmd), "*4\r\n$5\r\nLTRIM\r\n$%zu\r\n%s\r\n$%d\r\n%d\r\n$%d\r\n%d\r\n",
             strlen(list), list,
             (int)snprintf(NULL, 0, "%d", start), start,
             (int)snprintf(NULL, 0, "%d", end), end);
    if (redis_send_command(c, cmd, reply, sizeof(reply)) != 0) return 0;
    if (strncmp(reply, "+OK", 3) == 0) return 1;
    return 0;
}

// EXPIRE操作
int redis_expire(redisContext* c, const char* key, int seconds) {
    char cmd[256], reply[REDIS_REPLY_BUF];
    snprintf(cmd, sizeof(cmd), "*3\r\n$6\r\nEXPIRE\r\n$%zu\r\n%s\r\n$%d\r\n%d\r\n",
             strlen(key), key, (int)snprintf(NULL, 0, "%d", seconds), seconds);
    if (redis_send_command(c, cmd, reply, sizeof(reply)) != 0) return 0;
    if (reply[0] == ':') return atoi(reply + 1);
    return 0;
}

// TTL操作
int redis_ttl(redisContext* c, const char* key) {
    char cmd[256], reply[REDIS_REPLY_BUF];
    snprintf(cmd, sizeof(cmd), "*2\r\n$3\r\nTTL\r\n$%zu\r\n%s\r\n", strlen(key), key);
    if (redis_send_command(c, cmd, reply, sizeof(reply)) != 0) return -2;
    if (reply[0] == ':') return atoi(reply + 1);
    return -2;
}

// HSET操作
int redis_hset(redisContext* c, const char* hash, const char* field, const char* value) {
    char cmd[1024], reply[REDIS_REPLY_BUF];
    snprintf(cmd, sizeof(cmd), "*4\r\n$4\r\nHSET\r\n$%zu\r\n%s\r\n$%zu\r\n%s\r\n$%zu\r\n%s\r\n",
             strlen(hash), hash, strlen(field), field, strlen(value), value);
    if (redis_send_command(c, cmd, reply, sizeof(reply)) != 0) return -1;
    // :0\r\n 或 :1\r\n
    if (reply[0] == ':') {
        return atoi(reply + 1);
    }
    return -1;
}

// SET操作
int redis_set(redisContext* c, const char* key, const char* value) {
    char cmd[512], reply[REDIS_REPLY_BUF];
    snprintf(cmd, sizeof(cmd), "*3\r\n$3\r\nSET\r\n$%zu\r\n%s\r\n$%zu\r\n%s\r\n",
             strlen(key), key, strlen(value), value);
    if (redis_send_command(c, cmd, reply, sizeof(reply)) != 0) return 0;
    if (strncmp(reply, "+OK", 3) == 0) return 1;
    return 0;
}

// 断开连接
void redis_disconnect(redisContext* c) {
    if (c) {
        close(c->sockfd);
        free(c);
    }
}

/* 示例用法

// 将redisContext* c 定义为全局变量
redisContext* c = NULL;

int main() {
    // 从config.conf读取redis_ip和redis_port
    char redis_ip[128] = "127.0.0.1";
    int redis_port = 6379;
    FILE* conf = fopen("config.conf", "r");
    if (conf) {
        char line[256];
        while (fgets(line, sizeof(line), conf)) {
            if (strncmp(line, "redis_ip=", 9) == 0) {
                sscanf(line + 9, "%127s", redis_ip);
            } else if (strncmp(line, "redis_port=", 11) == 0) {
                sscanf(line + 11, "%d", &redis_port);
            }
        }
        fclose(conf);
    }
    c = redis_connect(redis_ip, redis_port);
    if (!c) return -1;

    
    // SET/GET
    redis_set(c, "foo", "bar");
    char* val = redis_get(c, "foo");
    if (val) {
        printf("GET foo: %s\n", val);
        free(val);
    }

    // HSET/HGET
    redis_hset(c, "myhash", "field1", "value1");
    char* hval = redis_hget(c, "myhash", "field1");
    if (hval) {
        printf("HGET myhash field1: %s\n", hval);
        free(hval);
    }

    // RPUSH/LPOP
    redis_rpush(c, "mylist", "item1");
    redis_rpush(c, "mylist", "item2");
    char* lval = redis_lpop(c, "mylist");
    if (lval) {
        printf("LPOP mylist: %s\n", lval);
        free(lval);
    }

    // LRANGE
    int count = 0;
    char** arr = redis_lrange(c, "mylist", 0, -1, &count);
    if (arr) {
        printf("LRANGE mylist 0 -1:\n");
        for (int i = 0; i < count; ++i) {
            printf("  [%d]: %s\n", i, arr[i]);
        }
        free_redis_array(arr, count);
    }

    // LTRIM
    if (redis_ltrim(c, "mylist", 0, 0)) {
        printf("LTRIM mylist 0 0 success\n");
    }

    // EXPIRE/TTL
    redis_set(c, "expirekey", "val");
    if (redis_expire(c, "expirekey", 10)) {
        printf("Set expire for expirekey 10s\n");
    }
    int ttl = redis_ttl(c, "expirekey");
    printf("TTL for expirekey: %d\n", ttl);



    // 测试刚刚补充的函数：redis_hset, redis_expire, redis_ttl, redis_ltrim

    // HSET
    int hset_ret = redis_hset(c, "myhash", "field2", "value2");
    if (hset_ret == 1) {
        printf("HSET myhash field2: new field set\n");
    } else if (hset_ret == 0) {
        printf("HSET myhash field2: field updated\n");
    } else {
        printf("HSET myhash field2: error\n");
    }
    char* hval2 = redis_hget(c, "myhash", "field2");
    if (hval2) {
        printf("HGET myhash field2: %s\n", hval2);
        free(hval2);
    }

    // EXPIRE
    redis_set(c, "expirekey2", "val2");
    int expire_ret = redis_expire(c, "expirekey2", 5);
    if (expire_ret == 1) {
        printf("EXPIRE expirekey2 5s: success\n");
    } else if (expire_ret == 0) {
        printf("EXPIRE expirekey2 5s: key does not exist or failed\n");
    } else {
        printf("EXPIRE expirekey2 5s: error\n");
    }

    // TTL
    int ttl2 = redis_ttl(c, "expirekey2");
    printf("TTL for expirekey2: %d\n", ttl2);

    // LTRIM
    redis_rpush(c, "trimlist", "a");
    redis_rpush(c, "trimlist", "b");
    redis_rpush(c, "trimlist", "c");
    int ltrim_ret = redis_ltrim(c, "trimlist", 1, 2);
    if (ltrim_ret == 1) {
        printf("LTRIM trimlist 1 2: success\n");
    } else {
        printf("LTRIM trimlist 1 2: failed\n");
    }
    int trim_count = 0;
    char** trim_arr = redis_lrange(c, "trimlist", 0, -1, &trim_count);
    if (trim_arr) {
        printf("LRANGE trimlist 0 -1 after LTRIM:\n");
        for (int i = 0; i < trim_count; ++i) {
            printf("  [%d]: %s\n", i, trim_arr[i]);
        }
        free_redis_array(trim_arr, trim_count);
    }



    redis_disconnect(c);
    return 0;
}*/
